﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Linq.Expressions;

using ProjectBase.Core;

namespace ProjectBase.Data
{
    public static partial class DaoExtensions
    {
        #region Xml - IsExact string
        /// <summary>
        ///     Compares two strings if they are Equal (contains the same char-set).
        ///     Attention: when the comparing 'value' parameter is null, true is returned anyway..
        /// </summary>
        /// <param name = "toBeCompared">The string which is filtered for match</param>
        /// <param name = "value">the value to be matched with the compared string.
        ///     Attention: when the comparing 'value' parameter is null, true is returned anyway..</param>
        /// <returns>True if 'value' parameter is null, or if there is a match</returns>
        public static bool IsExact(this string toBeCompared, string value)
        {
            if (value.IsNull())
            {
                return true;
            }
            return toBeCompared.IsEqual(value);
        }
        #endregion Xml - IsExact string

        #region Xml - IsEqual
        public static bool IsEqual<TSource, TID>(this TSource toBeCompared, TSource value)
            where TSource : IPersistentObjectWithTypedId<TID>
        {
            if (value.IsNull())
            {
                return true;
            }
            if (toBeCompared.IsNull())
            {
                return false;
            }
            return toBeCompared.ID.Equals(value.ID);
        }

        /// <summary>
        ///     Compares two strings if they are Equal (contains the same char-set).
        ///     Attention: when the comparing 'value' parameter is null, true is returned anyway..
        /// </summary>
        /// <param name = "toBeCompared">The string which is filtered for match</param>
        /// <param name = "value">the value to be matched with the compared string.
        ///     Attention: when the comparing 'value' parameter is null, true is returned anyway..</param>
        /// <returns>True if 'value' parameter is null, or if there is a match</returns>
        public static bool IsEqual<TSource>(this TSource toBeCompared, TSource? value)
            where TSource : struct
        {
            if (value.IsNull())
            {
                return true;
            }
            return toBeCompared.Equals(value);
        }

        /// <summary>
        ///     Compares two ValueTypes if they are Equal (contains the same value).
        ///     Attention: when the comparing 'value' parameter is null, true is returned anyway..
        /// </summary>
        /// <param name = "toBeCompared">The ValueType which will be comparing</param>
        /// <param name = "value">the value to be matched with the comparing ValueType value.
        ///     Attention: when the comparing 'value' parameter is null, true is returned anyway..</param>
        /// <returns>True if 'value' parameter is null, or if there is a match</returns>
        public static bool IsEqual<TSource>(this TSource? toBeCompared, TSource? value)
            where TSource : struct
        {
            if (value.IsNull())
            {
                return true;
            }
            return toBeCompared.Equals(value);
        }
        #endregion Xml - IsEqual

        #region Xml - Compare
        public static bool Compare<TSource>(this TSource? toBeCompared, TSource? value, Sign sign)
            where TSource : struct, IComparable<TSource>
        {
            if (toBeCompared.IsNull())
            {
                return value.IsNull();
            }
            return toBeCompared.Value.Compare(value, sign);
        }

        public static bool Compare<TSource>(this TSource toBeCompared, TSource? value, Sign sign)
            where TSource : struct, IComparable<TSource>
        {
            if (value.IsNull())
            {
                return true;
            }

            var compared = toBeCompared.CompareTo(value.Value);
            switch (sign)
            {
                case Sign.Greater:
                    return compared > 0;
                case Sign.GreaterOrEqual:
                    return compared >= 0;
                case Sign.Less:
                    return compared < 0;
                case Sign.LessOrEqual:
                    return compared <= 0;
                default:
                    return compared == 0;
            }
        }

        #endregion Xml - Compare

        #region Xml - IsLike
        /// <summary>
        ///     Compares two strings similar way as SQL LIKE. *val, val*, *val*, val - can be used.
        ///     But inner wild card 'v*al' will return false.
        ///     Attention: when the comparing 'value' parameter is null, true is returned anyway..
        /// </summary>
        /// <param name = "toCompare">The ValueType which will be comparing</param>
        /// <param name = "value">the value to be matched with the comparing ValueType value.
        ///     Attention: when comparing 'value' parameter is null, true is returned anyway..</param>
        /// <returns>True if 'value' parameter is null, or if there is a match</returns>
        public static bool IsLike(this string toCompare, string value)
        {
            var toBeCompared = toCompare ?? string.Empty;
            if (value.IsEmpty())
            {
                return true;
            }
            // Change % to *
            value = value.Replace(Const.Percentage, Const.Asterisk);
            // the pure string for final compare
            var cleanValue = value.Replace(Const.Asterisk, string.Empty);
            // abbrev for *value
            var startWith = value.StartsWith(Const.Asterisk, StringComparison.OrdinalIgnoreCase);
            // abbrev for value*
            var endWith = value.EndsWith(Const.Asterisk, StringComparison.OrdinalIgnoreCase);

            // exact match?
            var result = toBeCompared.IsEqual(cleanValue);

            // Is there any Like statement? (in fact only startWith and endWith like *value*)
            if (startWith || endWith)
            {
                // II. LIKE (contains)
                result = toBeCompared.ToLower().Contains(cleanValue.ToLower());
                if (!startWith)
                {
                    // III. only value* (toBeCompared must StartsWith)
                    result = toBeCompared.StartsWith(cleanValue, StringComparison.OrdinalIgnoreCase);
                }
                if (!endWith)
                {
                    // IV. only *value (toBeCompared must EndsWith)
                    result = toBeCompared.EndsWith(cleanValue, StringComparison.OrdinalIgnoreCase);
                }
            }
            return result;
        }
        public static bool IsNotLike(this string toCompare, string value)
        {
            if (value.IsEmpty())
            {
                return true;
            }
            return !toCompare.IsLike(value);
        }
        #endregion  Xml - IsLike

        #region OrderBy property builder
        public static IComparable BuildMember<T>(this T entity, string path)
        {
            var parameterEntity = Expression.Parameter(typeof(T));
            var parameterPath = Expression.Parameter(typeof(string));

            if (path.IsEmpty())
            {
                return null;
            }

            Expression body = parameterEntity;
            foreach (var name in path.Split('.'))
            {
                try
                {
                    var property = Expression.Property(body, name);
                    body = Expression.MakeMemberAccess(body, property.Member);
                }
                catch (ArgumentException)
                {
                    return null;
                }
            }
            if (body.IsNull())
            {
                return null;
            }

            var lambda = Expression.Lambda<Func<T, string, IComparable>>(
                Expression.Convert(body, typeof(IComparable)),
                parameterEntity,
                parameterPath);

            return lambda.Compile().Invoke(entity, path);
        }
        #endregion OrderBy property builder
    }
}